#include "complex.h"

Complex::Complex() : Constante(COMPLEX)
{
this->type=COMPLEX;
        this->real = new Integer(0);
        this->img = new Integer(1);
}

Complex::Complex(const Complex& c) : Constante(COMPLEX){

        switch(c.real->getType()){
                case Constante::INTEGER:
        this->real = new Integer(*static_cast<Integer*>(c.real));
                break;
                case Constante::RATIONNAL:
        this->real = new Fraction(*static_cast<Fraction*>(c.real));
                break;
                case Constante::REAL:
        this->real = new Real(*static_cast<const Real*>(c.real));
                break;
        }

        switch(c.img->getType()){
                case Constante::INTEGER:
        this->img = new Integer(*static_cast<const Integer*>(c.img));
                break;
                case Constante::RATIONNAL:
        this->img = new Fraction(*static_cast<const Fraction*>(c.img));
                break;
                case Constante::REAL:
        this->img = new Real(*static_cast<const Real*>(c.img));
                break;
        }
}

Complex::Complex(const NonComplexNumber*n1,const NonComplexNumber*n2) : Constante(COMPLEX){
this->type=COMPLEX;

        switch(n1->getType()){
                case Constante::INTEGER:
        this->real = new Integer(*static_cast<const Integer*>(n1));
                break;
                case Constante::RATIONNAL:
        this->real = new Fraction(*static_cast<const Fraction*>(n1));
                break;
                case Constante::REAL:
        this->real = new Real(*static_cast<const Real*>(n1));
                break;
        }

        switch(n2->getType()){
                case Constante::INTEGER:
        this->img = new Integer(*static_cast<const Integer*>(n2));
                break;
                case Constante::RATIONNAL:
        this->img = new Fraction(*static_cast<const Fraction*>(n2));
                break;
                case Constante::REAL:
        this->img = new Real(*static_cast<const Real*>(n2));
                break;
        }
}


Complex::Complex(const Integer& i) : Constante(COMPLEX){
this->type=COMPLEX;
        this->real = new Integer(i);
        this->img = new Integer(0);
}
Complex::Complex(const Fraction& f) : Constante(COMPLEX){
this->type=COMPLEX;
        this->real = new Fraction(f);
        this->img = new Integer(0);
}
Complex::Complex(const Real& r) : Constante(COMPLEX){
this->type=COMPLEX;
        this->real = new Real(r);
        this->img = new Integer(0);
}

Constante* Complex::operator+(const Constante& c)const{
        switch(c.getType()){
                case Constante::INTEGER:
        return *this+Complex(static_cast<const Integer&>(c));
                break;
                case Constante::RATIONNAL:
        return *this+Complex(static_cast<const Fraction&>(c));
                break;
                case Constante::REAL:
        return *this+Complex(static_cast<const Real&>(c));
                break;
                case Constante::COMPLEX:
        return new Complex(static_cast<NonComplexNumber*>(Addition::apply(*this->real,*static_cast<const Complex&>(c).real)),
                           static_cast<NonComplexNumber*>(Addition::apply(*this->img,*static_cast<const Complex&>(c).img)));
                break;
        }
}

Constante* Complex::operator*(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return new Complex(static_cast<NonComplexNumber*>(Multiplcation::apply(*this->real,static_cast<const Integer&>(c))),
                           static_cast<NonComplexNumber*>(Multiplcation::apply(*this->img,static_cast<const Integer&>(c))));
                case Constante::RATIONNAL:
        return new Complex(static_cast<NonComplexNumber*>(Multiplcation::apply(*this->real,static_cast<const Fraction&>(c))),
                           static_cast<NonComplexNumber*>(Multiplcation::apply(*this->img,static_cast<const Fraction&>(c))));
                case Constante::REAL:
        return new Complex(static_cast<NonComplexNumber*>(Multiplcation::apply(*this->real,static_cast<const Real&>(c))),
                           static_cast<NonComplexNumber*>(Multiplcation::apply(*this->img,static_cast<const Real&>(c))));
                break;
                case Constante::COMPLEX:
        return new Complex(
                static_cast<const NonComplexNumber*>(
                        Substartion::apply(
                                *Multiplcation::apply(*this->real,*static_cast<const Complex&>(c).real),
                                *Multiplcation::apply(*this->img,*static_cast<const Complex&>(c).img)
                        )
                ),
                static_cast<const NonComplexNumber*>(
                        Addition::apply(
                                *Multiplcation::apply(*this->real,*static_cast<const Complex&>(c).img),
                                *Multiplcation::apply(*this->img,*static_cast<const Complex&>(c).real)
                        )
                )
                );
                break;
        }
}

Constante* Complex::operator-(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return *this-Complex(static_cast<const Integer&>(c));
                case Constante::RATIONNAL:
        return *this-Complex(static_cast<const Fraction&>(c));
                case Constante::REAL:
        return *this-Complex(static_cast<const Real&>(c));
                break;
                case Constante::COMPLEX:
        return new Complex(static_cast<NonComplexNumber*>(Substartion::apply(*this->real,*static_cast<const Complex&>(c).real)),
                           static_cast<NonComplexNumber*>(Substartion::apply(*this->img,*static_cast<const Complex&>(c).img)));
                break;
        }
}

Constante* Complex::operator/(const Constante& c)const{

        switch(c.getType()){
                case Constante::INTEGER:
        return *this/Complex(static_cast<const Integer&>(c));
                case Constante::RATIONNAL:
        return *this/Complex(static_cast<const Fraction&>(c));
                case Constante::REAL:
        return *this/Complex(static_cast<const Real&>(c));
                break;
                case Constante::COMPLEX:

        return new Complex(
                static_cast<NonComplexNumber*>(
                        Division::apply(
                                *Addition::apply(
                                      *Multiplcation::apply(*this->real,*static_cast<const Complex&>(c).real),
                                     *Multiplcation::apply(*this->img,*static_cast<const Complex&>(c).img)
                                )
                           ,
                                *Addition::apply(
                                        *Multiplcation::apply(*static_cast<const Complex&>(c).real,*static_cast<const Complex&>(c).real),
                                        *Multiplcation::apply(*static_cast<const Complex&>(c).img,*static_cast<const Complex&>(c).img)
                                )
                        )
                ),
                static_cast<NonComplexNumber*>(
                        Division::apply(
                                *Substartion::apply(
                                        *Multiplcation::apply(*this->img,*static_cast<const Complex&>(c).real),
                                        *Multiplcation::apply(*this->real,*static_cast<const Complex&>(c).img)
                                )
                           ,
                                *Addition::apply(
                                        *Multiplcation::apply(*static_cast<const Complex&>(c).real,*static_cast<const Complex&>(c).real),
                                        *Multiplcation::apply(*static_cast<const Complex&>(c).img,*static_cast<const Complex&>(c).img)
                                )
                        )
                )
                );
                break;
        }
}

Constante* Complex::operator-()const{
        return new Complex((const NonComplexNumber*)-(*this->real),(const NonComplexNumber*)-(*this->img));
}

Complex::~Complex(){
        if(this->real)
                delete this->real;

        if(this->img)
                delete this->img;
}
